package com.quectel.core.module.household.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.quectel.constant.global.SqlConstants;
import com.quectel.constant.global.SystemConstants;
import com.quectel.util.aspect.lock.annotation.Lock;
import com.quectel.core.constants.RedisCacheConstants;
import com.quectel.core.constants.RedisLockConstants;
import com.quectel.core.module.car.dto.CarDto;
import com.quectel.core.module.car.service.CarService;
import com.quectel.core.module.household.dao.HouseholdDao;
import com.quectel.core.module.household.dto.*;
import com.quectel.core.module.household.dto.datav.HouseholdCountDto;
import com.quectel.core.module.household.entity.HouseholdEntity;
import com.quectel.core.module.household.service.HouseholdFamilyService;
import com.quectel.core.module.household.service.HouseholdRoomService;
import com.quectel.core.module.household.service.HouseholdService;
import com.quectel.core.module.household.service.HouseholdSocialRelationsService;
import com.quectel.core.module.parkingcard.dto.ParkingCardMemberDto;
import com.quectel.core.module.parkingcard.service.ParkingCardMemberService;
import com.quectel.core.module.village.dto.VillageRoomDto;
import com.quectel.core.module.village.service.VillageRoomService;
import com.quectel.core.module.village.service.VillageService;
import com.quectel.util.common.CopyUtils;
import com.quectel.util.common.JacksonUtils;
import com.quectel.util.kit.CacheKit;
import com.quectel.util.kit.Snowflake;
import com.quectel.util.mybatis.MyBatisPlusUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author caolu
 * @email louis.cao@quectel.com
 * @date 2021-11-02 13:11:28
 */
@DubboService
public class HouseholdServiceImpl implements HouseholdService {

    private static final Logger LOGGER = LoggerFactory.getLogger(HouseholdServiceImpl.class);

    private static final String HOUSEHOLD_CACHE_BY_ID = RedisCacheConstants.PROJECT_NAME + "HOUSEHOLD_CACHE_BY_ID:";
    private static final String HOUSEHOLD_CACHE_BY_VILLAGE_MOBILE = RedisCacheConstants.PROJECT_NAME + "HOUSEHOLD_CACHE_BY_VILLAGE_MOBILE:";

    @Autowired
    private HouseholdDao householdDao;

    @Autowired
    private VillageService villageService;
    @Autowired
    private VillageRoomService villageRoomService;

    @Autowired
    private HouseholdRoomService householdRoomService;


    @Autowired
    private HouseholdSocialRelationsService householdSocialRelationsService;

    @Autowired
    private HouseholdFamilyService householdFamilyService;
    @Autowired
    private CarService carService;
    @Autowired
    private ParkingCardMemberService parkingCardMemberService;


    @Override
    @Lock(
            lockExpresses = {
                    RedisLockConstants.HOUSEHOLD_LOCK + "#{#dto.householdId}"
            }
    )
    @Transactional
    public void saveOrUpdateRelations(HouseholdRelationsDto dto) {
        HouseholdDto householdDto = selectById(dto.getHouseholdId());
        if (householdDto == null) {
            return;
        }

        //批量保存社会关系
        if (CollectionUtils.isNotEmpty(dto.getHouseholdFamilyList())) {
            //删除社会关系
            householdFamilyService.deleteByHouseholdId(dto.getHouseholdId());

            for (HouseholdFamilyDto householdFamilyDto : dto.getHouseholdFamilyList()) {
                householdFamilyDto.setTenantId(householdDto.getTenantId());
                householdFamilyDto.setVillageId(householdDto.getVillageId());
                householdFamilyDto.setHouseholdId(dto.getHouseholdId());
                householdFamilyService.save(householdFamilyDto);
            }

        }

        //批量保存家庭关系
        if (CollectionUtils.isNotEmpty(dto.getSocialRelationsList())) {
            //删除家庭关系
            householdSocialRelationsService.deleteByHouseholdId(dto.getHouseholdId());

            for (HouseholdSocialRelationsDto householdSocialRelationsDto : dto.getSocialRelationsList()) {
                householdSocialRelationsDto.setTenantId(householdDto.getTenantId());
                householdSocialRelationsDto.setVillageId(householdDto.getVillageId());
                householdSocialRelationsDto.setHouseholdId(dto.getHouseholdId());
                householdSocialRelationsService.save(householdSocialRelationsDto);
            }

        }
    }

    @Override
    public List<VillageRoomDto> queryHasFocusHouseholdRooms(Long buildingId) {


        return villageRoomService.selectByBuildingId(buildingId)
                .stream()
                .filter(room -> {
                    List<HouseholdRoomDto> householdRoomDtos = householdRoomService.selectByRoomId(room.getId());
                    if (CollectionUtils.isEmpty(householdRoomDtos)) {
                        return false;
                    }
                    for (HouseholdRoomDto householdRoomDto : householdRoomDtos) {
                        HouseholdDto householdDto = householdRoomDto.getHouseholdDto();
                        if (householdDto != null) {
                            if (StringUtils.isNotBlank(householdDto.getTags())) {
                                Map parse = JacksonUtils.parse(householdDto.getTags(), Map.class);
                                if (parse.size() > 0) {
                                    return true;
                                }
                            }
                        }
                    }
                    return false;
                }).collect(Collectors.toList());
    }

    @Override
    public Map<String, Double> focusGroupsCount(Map<String, Object> params) {
        return householdDao.focusGroupsCount(params);
    }

    @Override
    public HouseholdCountDto countHousehold(Map<String, Object> params) {
        return householdDao.countHousehold(params);
    }

    @Override
    public List<HouseholdDto> selectByMobile(String mobile) {
        List<HouseholdEntity> entityList = householdDao.selectList(
                new LambdaQueryWrapper<HouseholdEntity>()
                        .eq(HouseholdEntity::getMobile, mobile)
        );
        return CopyUtils.copyList(entityList, HouseholdDto.class);
    }

    @Override
    public HouseholdDto selectCacheByVillageIdAndMobile(Long villageId, String mobile) {
        return CacheKit.cacheToRedis(
                () -> selectByVillageIdAndMobile(villageId, mobile),
                HOUSEHOLD_CACHE_BY_VILLAGE_MOBILE + SystemConstants.COLON + villageId + SystemConstants.COLON + mobile,

                SystemConstants.NOT_NULL_CACHE_EXPIRE_SECONDS
        );
    }

    @Override
    public HouseholdDto selectByVillageIdAndMobile(Long villageId, String mobile) {
        HouseholdEntity entity = householdDao.selectOne(
                new LambdaQueryWrapper<HouseholdEntity>()
                        .eq(HouseholdEntity::getVillageId, villageId)
                        .eq(HouseholdEntity::getMobile, mobile)
                        .last(SqlConstants.MYSQL_LIMIT_ONE)
        );
        return paddingField(CopyUtils.copyObj(entity, HouseholdDto.class));
    }

    @Override
    public HouseholdDto selectCacheById(Long id) {
        return CacheKit.cacheToRedis(
                () -> selectById(id),
                HOUSEHOLD_CACHE_BY_ID + id,

                SystemConstants.NOT_NULL_CACHE_EXPIRE_SECONDS
        );
    }

    @Override
    public HouseholdDto selectById(Long id) {
        HouseholdEntity entity = householdDao.selectById(id);
        return paddingField(CopyUtils.copyObj(entity, HouseholdDto.class));
    }

    @Override
    public List<HouseholdDto> queryList(Map<String, Object> params) {
        List<HouseholdEntity> list = householdDao.queryList(params);
        List<HouseholdDto> result = CopyUtils.copyList(list, HouseholdDto.class);
        result.forEach(this::paddingField);
        return result;
    }

    private HouseholdDto paddingField(HouseholdDto dto) {
        if (dto != null) {
            dto.setVillageDto(villageService.selectById(dto.getVillageId()));
        }
        return dto;
    }

    @Override
    public int queryTotal(Map<String, Object> params) {
        return householdDao.queryTotal(params);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long save(HouseholdDto dto) {
        HouseholdEntity entity = CopyUtils.copyObj(dto, HouseholdEntity.class);
        entity.setId(Snowflake.nextId());
        householdDao.insert(entity);
        dto.setId(entity.getId());
        return entity.getId();
    }

    @Override
    public void updateById(HouseholdDto dto) {
        HouseholdEntity entity = CopyUtils.copyObj(dto, HouseholdEntity.class);
        householdDao.updateById(entity);
        CacheKit.invalidRedisCache(HOUSEHOLD_CACHE_BY_ID + dto.getId());
    }

    private void saveHouseholdRoom(HouseholdDto householdDto) {
        householdRoomService.deleteByHouseholdId(householdDto.getId());
        if (householdDto.getHouseholdRoomDtoList() != null) {
            for (HouseholdRoomDto villageRoomDto : householdDto.getHouseholdRoomDtoList()) {
                villageRoomDto.setHouseholdId(householdDto.getId());
                householdRoomService.save(villageRoomDto);
            }
        }
    }

    /**
     * 住户信息变更，更新停车部分的信息
     * @param o 旧的住户信息
     * @param n 新的住户信息
     */
    private void updateParkingPartInfo(HouseholdDto o, HouseholdDto n) {
        if (StringUtils.isEmpty(o.getMobile())){
            return;
        }
        if (o == null || n == null) {
            return ;
        }
        if (o.getMobile().equals(n.getMobile())
                && o.getName().equals(n.getName())) {
            return ;
        }
        List<CarDto> carDtos = carService.selectByMobile(o.getMobile());
        for (CarDto carDto : carDtos) {
            CarDto newlyDto = new CarDto();
            newlyDto.setId(carDto.getId());
            newlyDto.setOwnerMobile(n.getMobile());
            newlyDto.setOwnerName(n.getName());
            carService.updateById(newlyDto);

            ParkingCardMemberDto parkingCardMemberDto = parkingCardMemberService.selectByCarId(carDto.getId());
            if (Objects.nonNull(parkingCardMemberDto)) {
                ParkingCardMemberDto newlyMember = new ParkingCardMemberDto();
                newlyMember.setId(parkingCardMemberDto.getId());
                newlyMember.setMobile(n.getMobile());
                parkingCardMemberService.updateById(newlyMember);
            }
        }
    }

    @Override
    public void updateAllColumnById(HouseholdDto dto) {

        HouseholdEntity entity = CopyUtils.copyObj(dto, HouseholdEntity.class);


        MyBatisPlusUtils.updateAllColumnById(entity, householdDao);

        CacheKit.invalidRedisCache(HOUSEHOLD_CACHE_BY_ID + dto.getId());


    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveOrUpdateHouseholdAndRoom(HouseholdDto householdDto) {
        if (householdDto.getId() == null) {
            Long id = save(householdDto);
            householdDto.setId(id);
        } else {
            HouseholdDto oldDto = selectCacheById(householdDto.getId());
            // 住户信息变更，停车相关的信息可能需要变更
            updateParkingPartInfo(oldDto, householdDto);
            updateById(householdDto);
        }
        saveHouseholdRoom(householdDto);
    }

    @Override
    public void deleteById(Long id) {
        householdDao.deleteById(id);

        householdRoomService.deleteByHouseholdId(id);

        CacheKit.invalidRedisCache(HOUSEHOLD_CACHE_BY_ID + id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteBatch(Long[] ids) {
        for (Long id : ids) {
            deleteById(id);
        }
    }
}
